package com.cloudbroker.bcs.platform.dav.common.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cloudbroker.bcs.common.configure.ConfigUtil;
import com.cloudbroker.bcs.common.util.IOUtil;
import com.cloudbroker.bcs.common.util.ReflectionUtil;
import com.cloudbroker.bcs.common.util.StringUtil;
import com.cloudbroker.bcs.common.util.ValueUtil;
import com.cloudbroker.bcs.platform.dav.bizapi.constants.HSBCPSFields;
import com.cloudbroker.bcs.platform.dav.bizapi.constants.IFSFunctionIdsNew;
import com.cloudbroker.bcs.platform.dav.bizapi.service.base.vo.HSBCPSVO;
import com.cloudbroker.bcs.platform.dav.common.constant.HttpConstant;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HttpUtil {
    private static final Logger logger = LoggerFactory.getLogger(HttpUtil.class);

	private static final CloseableHttpClient httpClient;
    private static final RequestConfig requestConfig;
	public static final String CHARSET = "UTF-8";
    public static final  int MAX_TOTAL_CONNECTIONS = 2000;//连接池最大并发连接数
    public static final  int MAX_ROUTE_CONNECTIONS = 2000;//单路由最大并发数
    public static final  int CONNECT_TIMEOUT = 9000;
    public static final  int SOCKET_TIMEOUT = 6000;

	static {
		PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
		cm.setMaxTotal(MAX_TOTAL_CONNECTIONS);
		cm.setDefaultMaxPerRoute(MAX_ROUTE_CONNECTIONS);
		httpClient = HttpClients.custom().setConnectionManager(cm).build();
        requestConfig = RequestConfig.custom().setSocketTimeout(SOCKET_TIMEOUT).setConnectTimeout(CONNECT_TIMEOUT).build();
    }

	public static HttpGet createHttpGet(String url) {
		HttpGet get = new HttpGet(url);
		get.setConfig(requestConfig);
		return get;
	}

	public static HttpPost createHttpPost(String url, List<NameValuePair> pairs) {
		HttpPost post = new HttpPost(url);
		post.setConfig(requestConfig);
		try {
			if (pairs != null && pairs.size() > 0) {
				post.setEntity(new UrlEncodedFormEntity(pairs, CHARSET));
			}
		}catch (Exception e) {
			logger.error("create http post error " , e);
		}
		return post;
	}

	public static List<NameValuePair> convertPairs(Map<String, Object> params) {
		if( null != params && !params.isEmpty() ) {
			List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
			for (Map.Entry<String, Object> entry : params.entrySet()) {
				String value = ValueUtil.getString(entry.getValue());
				if (value != null) {
					pairs.add(new BasicNameValuePair(entry.getKey(), value));
				}
			}
			return pairs;
		}
		return null;
	}

	public static List<NameValuePair> convertPairs(HSBCPSVO form) {
		if( null != form ) {
			Map<String,Field> fieldMap = ReflectionUtil.listAllFields(form.getClass());
			List<NameValuePair> pairs = new ArrayList<NameValuePair>(fieldMap.size());
			for (Map.Entry<String, Field> entry : fieldMap.entrySet()) {
				String value = ValueUtil.getString(ReflectionUtil.getValueRough(form , entry.getValue()));
				pairs.add(new BasicNameValuePair(entry.getKey(), value));
			}
			return pairs;
		}
		return null;
	}

	public static String doXmlPost(String url,String xml){
		HttpPost post = new HttpPost(url);
		try {
			StringEntity entity = new StringEntity(xml);
			post.setEntity(entity);
			post.setHeader("Content-Type", "text/xml;charset=UTF-8");
			CloseableHttpResponse httpResponse = httpClient.execute(post);
			String result = acquireResult(httpResponse,post);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static String doGet(String url, Map<String, Object> params) {
		return doGet(url, convertPairs(params), CHARSET);
	}

	public static String doGet(String url, HSBCPSVO form) {
		return doGet(url, convertPairs(form), CHARSET);
	}

	public static String doPost(String url, Map<String, Object> map) {
		return doPost(url, convertPairs(map), CHARSET , null);
	}

	public static String doPost(String url, Map<String, Object> map , Map<String,String> headerMap) {
		return doPost(url, convertPairs(map), CHARSET , headerMap);
	}

	public static String doPost(String url, HSBCPSVO form , Map<String,String> headerMap) {
		return doPost(url, convertPairs(form), CHARSET , headerMap);
	}

	/**
	 * HTTP Get 获取内容
	 * 
	 * @param url
	 *            请求的url地址 ?之前的地址
	 * @param params
	 *            请求的参数
	 * @param charset
	 *            编码格式
	 * @return 页面内容
	 */
	public static String doGet(String url, List<NameValuePair> params, String charset) {
		CloseableHttpResponse response = null;
		if (StringUtils.isBlank(url)) {
			return null;
		}
        HttpGet httpGet = null;
        try {
			if (params != null && !params.isEmpty()) {
				url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(params, charset));
			}
			httpGet = createHttpGet(url);
			response = httpClient.execute(httpGet);
			return acquireResult(response , httpGet);
		} catch (Exception e) {
			logger.error("do get error " , e);
		} finally {
			IOUtil.close(response);
            httpGet.releaseConnection();
		}
		return null;
	}

	/**
	 * HTTP Post 获取内容
	 * 
	 * @param url
	 *            请求的url地址 ?之前的地址
	 * @param map
	 *            请求的参数
	 * @param charset
	 *            编码格式
	 * @return 页面内容
	 */
	public static String doPost(String url, List<NameValuePair> map, String charset , Map<String,String> headerMap) {
		CloseableHttpResponse response = null;
		if (StringUtils.isBlank(url)) {
			return null;
		}
        HttpPost httpPost = null;
        try {
			httpPost = createHttpPost(url , map);
			if( null != headerMap && !headerMap.isEmpty() ) {
				for (Map.Entry<String, String> entry : headerMap.entrySet()) {
					httpPost.addHeader(entry.getKey(), entry.getValue());
				}
			}
			response = httpClient.execute(httpPost);
			return acquireResult(response,httpPost);
		} catch (Exception e) {
			logger.error("do post error " , e);
		} finally {
			IOUtil.close(response);
            httpPost.releaseConnection();
		}
		return null;
	}

	public static String doGet(String url, Map<String, Object> params,
								 String charSet,String authorization) {
		try {
			if (params != null && !params.isEmpty()) {
				url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(convertPairs(params), CHARSET));
			}
			HttpGet get = createHttpGet(url);
			get.setHeader("Content-Type", HttpConstant.CONTENT_TYPE_FORM);
			get.setHeader("Authorization", authorization);
			HttpResponse response = httpClient.execute(get);
			int status = response.getStatusLine().getStatusCode();
			HttpEntity entity = null;
			try {
				entity = response.getEntity();
				if (entity != null) {
					String result=EntityUtils.toString(entity, charSet);
					return result;
				}
			} catch (Exception e) {
				logger.error("do get error and status = " + status , e);
			} finally {
				IOUtil.close(entity.getContent());
			}
		} catch (Exception e) {
			logger.error("do get error " , e);
		}
		return null;
	}

	public static String doPost(String url, Map<String, Object> params,
								String charSet, String charsetReturn,
								String authorization) {
		try {
			HttpPost post = createHttpPost(url , convertPairs(params));
			post.setHeader("Content-Type", HttpConstant.CONTENT_TYPE_FORM);
			post.setHeader("Authorization", authorization);
			HttpResponse response = httpClient.execute(post);
			int status = response.getStatusLine().getStatusCode();
			HttpEntity entity = null;
			try {
				entity = response.getEntity();
				if (entity != null) {
					return EntityUtils.toString(entity, charsetReturn);
				}
			} catch (Exception e) {
				logger.error("do post error and status = " + status , e);
			} finally {
				if (entity != null) {
					entity.getContent().close();
				}
			}
		} catch (Exception e) {
			logger.error("do post error " , e);
		}
		return null;
	}

	/**
	 * 通过HttpClient的post请求 上传文件
	 *
	 * @param key file文件的参数名
	 * @param file 待上传的文件
	 * @param url 文件上传的url
	 *
	 * @return String 服务器返回json字符串
	 * */
	public static String doPost(String key , File file , String url) {
		CloseableHttpResponse response = null;
		if (StringUtils.isBlank(url)) {
			return null;
		}
        HttpPost httppost = null;
        try {
			httppost = createHttpPost(url , null);
			MultipartEntityBuilder builder = MultipartEntityBuilder.create();
			builder.addBinaryBody(key , file);
			httppost.setEntity(builder.build());
			response = httpClient.execute(httppost);
			return acquireResult(response , httppost);
		} catch (Exception e) {
			logger.error("do post error " , e);
		} finally {
			IOUtil.close(response);
            httppost.releaseConnection();
		}
		return null;
	}

	/**
	 *	通过HttpClient的get请求下载文件
	 *
	 * 	@param url 文件下载的指定url
	 *
	 * 	@return InputStream 文件流
	 * 		如果未取到文件,则InputStream为null
	 * */
	private static InputStream doGetDownload(String url) {
		CloseableHttpResponse response = null;
		InputStream ips = null;
		if (StringUtils.isBlank(url)) {
			return null;
		}
        HttpGet httpGet = null;
        try {
			httpGet = createHttpGet(url);
			response = httpClient.execute(httpGet);
			ips = response.getEntity().getContent();
			String base64 = "";
			//通过base64复制流,以做到防止response关闭时把流关闭
			if( (base64 = IOUtil.streamToBase64String(ips)).length() != 0 ) {
				ips = IOUtil.base64StringToStream(base64);
			} else {
				return null;
			}
		} catch (Exception e) {
			logger.error("do post error " , e);
		} finally {
			IOUtil.close(response);
            httpGet.releaseConnection();
		}
		return ips;
	}

	/***
	 * 获取Http Get/Post请求中返回的数据
	 * @param response	服务器返回response
	 * @param requestBase HttpGet/HttpPost 对象
	 *
	 * @return String 服务器返回数据
	 * */
	private static String acquireResult(CloseableHttpResponse response , HttpRequestBase requestBase) throws IOException {
		int statusCode = response.getStatusLine().getStatusCode();
		if (statusCode != HttpStatus.SC_OK) {
			requestBase.abort();
			throw new RuntimeException("HttpClient,error status code :" + statusCode);
		}
		HttpEntity entity = response.getEntity();
		String result = null;
		if (entity != null) {
			result = EntityUtils.toString(entity, "utf-8");
		}
		EntityUtils.consume(entity);
		return result;
	}

	/**
	 * 根据ConfigUtil获取访问Uag请求的url前缀
	 * */
	private static String getFunctionUrlPrefix() {
		String url = ConfigUtil.get("interface.uag.addr","http://127.0.0.1:21100/hsbc_operate/");
		if (!url.endsWith("/")) {
			url = url + "/";
		}
		return url;
	}

	/**
	 * 使用HttpClient的post请求调用中台功能号
	 *
	 * @param functionId 中台功能号
	 * @param map 请求体内容
	 *
	 * @return 服务器返回内容
	 * */
	public static String doPostFunc(String functionId, Map<String, Object> map) {
		String url = getFunctionUrlPrefix();
		url += functionId;
		return doPost(url, map);
	}

	/**
	 * 调用中台默认下载文件的功能接口进行文件下载
	 *
	 * @param key 下载文件名
	 *
	 * @return InputStream 下载的文件流
	 * */
	public static InputStream doDownloadFunc(String key) {
		return doDownloadFunc(null , key);
	}

	/**
	 * 调用中台指定的下载文件的功能接口进行文件下载
	 *
	 * @param functionId 中台指定的功能号
	 * @param key 下载文件名
	 *
	 * @return InputStream 下载的文件流
	 * */
	private static InputStream doDownloadFunc(String functionId, String key) {
		if(StringUtil.isBlank(functionId) ) {
			functionId = IFSFunctionIdsNew.IFSCommonFuncIds.FUNC_DOWNLOAD_FILE;
		}
		String url = getFunctionUrlPrefix();
		url = url + "download/" + functionId + "/" + key;
		return doGetDownload(url);
	}

	/**
	 * 调用中台默认的接口进行文件上传
	 *
	 * @param file 待上传文件
	 * @param key 待上传文件的键值
	 *
	 * @return String 服务器返回内容
	 * */
	public static String doPostUploadFunc(File file , String key) {
		return doPostUploadFunc(null , file , key);
	}

	/**
	 * 调用中台指定的上传文件的功能接口进行文件上传
	 *
	 * @param functionId 中台指定的功能号
	 * @param file 待上传文件
	 * @param key 待上传文件的键值
	 *
	 * @return String 服务器返回内容
	 * */
	public static String doPostUploadFunc(String functionId, File file, String key) {
		if(StringUtil.isBlank(functionId) ) {
			functionId = IFSFunctionIdsNew.IFSCommonFuncIds.FUNC_UPLOAD_FILE;
		}
		String url = getFunctionUrlPrefix();
		url = url + "upload/" + file.length() + "/" + key + "/" + functionId;
		return doPost(HSBCPSFields.FILE , file , url);
	}

	public static String getBrower(String userAgent){
		String brower = "";
		Map<String,String> browerMap = new HashMap<>();
		browerMap.put("SogouMobileBrowser","搜狗手机浏览器");
		browerMap.put("UCBrowser","UC浏览器");
		browerMap.put("UCWEB","UC浏览器");
		browerMap.put("Opera","Opera浏览器");
		browerMap.put("QQBrowser","QQ浏览器");
		browerMap.put("TencentTraveler","QQ浏览器");
		browerMap.put("MetaSr","搜狗浏览器");
		browerMap.put("360SE","360浏览器");
		browerMap.put("The world","世界之窗浏览器");
		browerMap.put("Maxthon","遨游浏览器");
		browerMap.put("Chrome","谷歌浏览器");
		browerMap.put("Safari","Safari浏览器");
		for(Map.Entry<String,String> entry : browerMap.entrySet()){
			if (userAgent.indexOf(entry.getKey()) != -1){
				brower = entry.getValue();
				break;
			}
		}
		if("".equals(brower)){
			brower = "未知浏览器";
		}
		return brower;
	}

	public static String getOs(String userAgent){
		String operatingSystem = "";
		Map<String,String> osMap = new HashMap<>();
		osMap.put("Windows NT 10.0","Windows 10");
		osMap.put("Windows NT 6.4","Windows 10");
		osMap.put("Windows NT 6.3","Windows 8.1");
		osMap.put("Windows NT 6.2","Windows 8");
		osMap.put("Windows NT 6.0","Windows 8");
		osMap.put("Windows NT 6.1","Windows 7");
		osMap.put("Windows NT 5.1","Windows XP");
		for(Map.Entry<String,String> entry : osMap.entrySet()){
			if (userAgent.indexOf(entry.getKey()) != -1){
				operatingSystem = entry.getValue();
				break;
			}
		}
		if("".equals(operatingSystem)){
			operatingSystem = "未知操作系统";
		}
		return operatingSystem;
	}

	public static String getPhoneFlag(String userAgent){
		String phoneFlag = "1";
		if(userAgent.indexOf("Mobile") == -1){
			phoneFlag = "0";
		}
		return phoneFlag;
	}

	public static String getAddressByIp(String ip){
		String address;
		String url = "http://int.dpool.sina.com.cn/iplookup/iplookup.php";
		Map<String,Object> param = new HashMap();
		param.put("format","json");
		param.put("ip",ip);
		try {
			JSONObject resMap = JSON.parseObject(doGet(url,param));
			if(resMap.get("country") != null){
				address = String.valueOf(resMap.get("country")) + resMap.get("province")+"省"+resMap.get("city")+"市";
			}else {
				address = "未知地址";
			}
		}catch (Exception e){
			logger.info(e.getMessage());
			address = "未知地址";
		}
		return address;
	}
}